home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1992 by Panagiotis Tsirigotis
- * All rights reserved. The file named COPYRIGHT specifies the terms
- * and conditions for redistribution.
- */
-
- static char RCSid[] = "$Id: connection.c,v 5.2 1992/11/10 08:18:25 panos Exp $" ;
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <syslog.h>
-
- #include "fsma.h"
- #include "sio.h"
-
- #include "connection.h"
- #include "state.h"
-
- static fsma_h connection_allocator ;
-
- char *inet_ntoa() ;
-
- void msg() ;
- void out_of_memory() ;
-
-
- status_e conn_init()
- {
- int flags = FSM_RETURN_ERROR ;
-
- #ifdef DEBUG
- flags |= FSM_ZERO_FREE ;
- #endif
- connection_allocator = fsm_create( sizeof( connection_s ), 0, flags ) ;
- return( ( connection_allocator == NULL ) ? FAILED : OK ) ;
- }
-
-
- /*
- * Get a connection for the specified service and return a pointer
- * to a new struct connection
- */
- connection_s *conn_new( sp )
- struct service *sp ;
- {
- connection_s new_conn ;
- register connection_s *cp ;
- char *func = "conn_new" ;
- status_e get_connection() ;
-
- CLEAR( new_conn ) ;
-
- /*
- * The reason we first get the connection and then allocate a
- * struct connection is because we want to always consume some
- * input.
- */
- if ( get_connection( sp, &new_conn ) == FAILED )
- return( NULL ) ;
-
- new_conn.state = CONN_OPEN ;
- new_conn.sp = sp ;
- SVC_HOLD( sp ) ;
-
- cp = COP( fsm_alloc( connection_allocator ) ) ;
- if ( cp == NULL )
- {
- out_of_memory( func ) ;
- conn_cleanup( &new_conn ) ;
- conn_shutdown( &new_conn ) ;
- conn_free( &new_conn ) ;
- return( NULL ) ;
- }
- *cp = new_conn ;
- return( cp ) ;
- }
-
-
- PRIVATE status_e get_connection( sp, cp )
- struct service *sp ;
- register connection_s *cp ;
- {
- int sin_len = sizeof( cp->remote_address ) ;
- register struct service_config *scp = CONF( sp ) ;
- char *func = "get_connection" ;
-
- if ( ACCEPTS_CONNECTIONS( scp ) )
- {
- cp->descriptor = accept( SVC_FD( sp ),
- SA( &cp->remote_address ), &sin_len ) ;
- if ( cp->descriptor == -1 )
- {
- msg( LOG_ERR, func, "service %s, accept: %m", scp->id ) ;
- return( FAILED ) ;
- }
- M_SET( cp->flags, COF_HAVE_ADDRESS ) ;
- M_SET( cp->flags, COF_NEW_DESCRIPTOR ) ;
- }
- else
- {
- if ( scp->socket_type == SOCK_DGRAM )
- {
- char t_ch ;
-
- /*
- * This trick is done to get the remote address.
- * select(2) guaranteed that we won't block on the recvfrom
- */
- if ( recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK,
- SA( &cp->remote_address ), &sin_len ) == -1 )
- {
- msg( LOG_ERR, func, "service %s, recvfrom: %m", scp->id ) ;
- return( FAILED ) ;
- }
- M_SET( cp->flags, COF_HAVE_ADDRESS ) ;
- }
- cp->descriptor = SVC_FD( sp ) ;
- }
- return( OK ) ;
- }
-
-
- /*
- * Close the connection descriptor if it is a new one
- */
- void conn_close( cp )
- register connection_s *cp ;
- {
- if ( cp->state == CONN_OPEN && M_IS_SET( cp->flags, COF_NEW_DESCRIPTOR ) )
- {
- (void) close( cp->descriptor ) ;
- cp->state = CONN_CLOSED ;
- }
- }
-
-
- /*
- * Release the specified connection.
- * Certain actions may be performed before doing this:
- * - invocation of the service shutdown function
- * - drain of a single UDP packet if the socket type is SOCK_DGRAM
- */
- void conn_free( cp )
- register connection_s *cp ;
- {
- register struct service *sp = cp->sp ;
- void drain() ;
-
- if ( cp->state == CONN_OPEN )
- {
- if ( M_IS_SET( cp->flags, COF_SHUTDOWN ) )
- svc_shutdown( sp, cp ) ;
-
- if ( M_IS_SET( cp->flags, COF_CLEANUP ) &&
- CONF( cp->sp )->socket_type == SOCK_DGRAM )
- drain( cp->descriptor ) ;
- }
-
- if ( SVC_RELE( sp ) == 0 )
- pset_remove( SERVICES( ps ), sp ) ;
-
- conn_close( cp ) ;
-
- fsm_free( connection_allocator, (char *)cp ) ;
- }
-
-
- /*
- * Since at present only special services are added as alternatives
- * we do not increase the reference count on alternative services.
- */
- status_e conn_add_alternative( cp, sp )
- register connection_s *cp ;
- struct service *sp ;
- {
- char *func = "conn_add_alternative" ;
-
- if ( sp == NULL )
- return( FAILED ) ;
-
- if ( cp->alternative_count >= MAX_ALTERNATIVES )
- {
- msg( LOG_ERR, func,
- "Cannot add alternative service %s to connection for service %s",
- CONF( sp )->id, CONF( cp->sp )->id ) ;
- return( FAILED ) ;
- }
-
- if ( debug.on )
- msg( LOG_DEBUG, func,
- "Adding alternative service %s to connection of service %s",
- CONF( sp )->id, CONF( cp->sp )->id ) ;
-
- cp->alternatives[ cp->alternative_count++ ] = sp ;
- return( OK ) ;
- }
-
-
- /*
- * Start invoking alternative services starting from the next alternative one
- * until either we get a successful invocation or we run out of services
- */
- status_e conn_start_alternative( cp )
- register connection_s *cp ;
- {
- char *func = "conn_start_alternative" ;
-
- while ( cp->next_alternative < cp->alternative_count )
- {
- struct service *asp = cp->alternatives[ cp->next_alternative++ ] ;
-
- if ( SVC_HANDLE( asp, cp ) == OK )
- {
- if ( debug.on )
- msg( LOG_DEBUG, func,
- "Started alternative service %s", CONF( asp )->id ) ;
- return( OK ) ;
- }
- }
- return( FAILED ) ;
- }
-
-
- void conn_dump( cp, fd )
- connection_s *cp ;
- int fd ;
- {
- unsigned u ;
- void tabprint() ;
-
- tabprint( fd, 1, "state = %s\n",
- ( cp->state == CONN_CLOSED ) ? "CLOSED" : "OPEN" ) ;
- tabprint( fd, 1, "service = %s\n", CONF( cp->sp )->id ) ;
- tabprint( fd, 1, "descriptor = %d\n", cp->descriptor ) ;
- tabprint( fd, 1, "flags = %#x\n", cp->flags ) ;
- tabprint( fd, 1, "remote_address = %s,%d\n",
- inet_ntoa( cp->remote_address.sin_addr ),
- ntohs( cp->remote_address.sin_port ) ) ;
- tabprint( fd, 1, "Alternative services = " ) ;
- for ( u = 0 ; u < cp->alternative_count ; u++ )
- Sprint( fd, " %s", CONF( cp->alternatives[ u ] )->id ) ;
- Sputchar( fd, '\n' ) ;
- if ( cp->alternative_count > 0 )
- tabprint( fd, 1, "next alternative service = %s\n",
- CONF( cp->alternatives[ cp->next_alternative ] )->id ) ;
- }
-
-